﻿using System;
using System.IO;
using System.Collections.Generic;

namespace LBNet
{
    public delegate void ProtocolHandler(object o);

    public class Protocol
    {
        public void RegisterMsg(ushort opCode, string msgType, ProtocolHandler h)
        {
            mProtocolHandlers[opCode] = new ProtocolInfo(msgType, h);
        }

        private struct ProtocolInfo
        {
            public string name;
            public ProtocolHandler handler;

            public ProtocolInfo(string n, ProtocolHandler h)
            {
                name = n;
                handler = h;
            }
        }
        private Dictionary<ushort, ProtocolInfo> mProtocolHandlers = new Dictionary<ushort, ProtocolInfo>();
        private bool HasMsg(ushort type)
        {
            return mProtocolHandlers.ContainsKey(type);
        }

        private class ProtocolMsg
        {
            public ProtocolHandler handler;
            public object msg;
        }
        private Queue<ProtocolMsg> ProtocolMsgs = new Queue<ProtocolMsg>();
        private void EnqueueProtocolMsg(ProtocolHandler handler, object msg)
        {
            ProtocolMsg pMsg = new ProtocolMsg();
            pMsg.handler = handler;
            pMsg.msg = msg;
            lock (ProtocolMsgs)
            {
                ProtocolMsgs.Enqueue(pMsg);
            }
        }
        private ProtocolMsg DequeueProtocolMsg()
        {
            lock (ProtocolMsgs)
            {
                if (ProtocolMsgs.Count > 0)
                    return ProtocolMsgs.Dequeue();
            }
            return null;
        }

        //接收协议
        public void ReceiveProtocol(object src, NetEventArg_Received mea)
        {
            int nDataSize = mea.BufferSize;
            if (nDataSize <= 0 || nDataSize > NetDefine.BUFFER_LENGTH)
                return;
            if (!BitConverter.IsLittleEndian)
                Array.Reverse(mea.Buffer, 0, NetDefine.HEAD_OP_SIZE);
            ushort type = BitConverter.ToUInt16(mea.Buffer, 0);
            if (!HasMsg(type))
            {
                PLDebug.LogWarning("unknown protocol type:" + type);
                return;
            }

            //NetTool.Log(type);

            ProtocolInfo protocolInfo = mProtocolHandlers[type];
            MemoryStream memStream = new MemoryStream(mea.Buffer, NetDefine.HEAD_OP_SIZE, nDataSize - NetDefine.HEAD_OP_SIZE);
            try
            {
                object msg = null;

                //这里使用ProtoBuf 反序列化
                //if (protocolInfo.name != "")
                   // msg = ProtoBuf.Meta.RuntimeTypeModel.Default.Deserialize(memStream, null, Type.GetType(protocolInfo.name));

                EnqueueProtocolMsg(protocolInfo.handler, msg);
            }
            catch (Exception e)
            {
                NetTool.LogError("ProtoBuf Deserialize Failed: Type[" + type.ToString() + "],Name[" + protocolInfo.name + "]\n" + e.ToString());
            }

            memStream.Close();

        }

        public void ProcessMsg()
        {
            for (int i = 0; i < 5; i++)
            {
                ProtocolMsg pMsg = DequeueProtocolMsg();
                if (pMsg == null)
                    return;

                pMsg.handler.Invoke(pMsg.msg);
            }
        }
    }
}
